//#include "stdafx.h"
#include "CSessionShm.h"
#include <string.h>
#ifdef WIN32
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
#endif


CSessionShm::CSessionShm()
{

	//m_hShareMem	= NULL;
	m_hMapFile	= NULL;
	m_pShareMemMap = NULL;
	m_nShareMemSize = 0;
	m_bIsCreated = false;

	m_lRowNum = 0;
	m_lVolNum = 0;
	m_lUpdateTime = 0;
	
	m_tFieldList.clear();

	memset(m_szShareMemName,0,sizeof(m_szShareMemName));
        printf("####################################################\n");
}

CSessionShm::~CSessionShm()
{
	Shm_Close();
	if(m_bIsCreated)
		Shm_Delete();
}

int	 CSessionShm::AddFields(char *inFieldName, int inFieldLen, bool bIsKeyField)
{
	if (NULL == inFieldName || inFieldLen <= 0)
		return -1;
	if(m_nShareMemSize > 0)
		return -3;

	CFieldList::const_iterator item = m_tFieldList.begin();

	while (item != m_tFieldList.end())
	{
		if(strcmp(inFieldName, (*item)->szFieldName) == 0)
			return -2;
		
		item++;	
	}

	FieldItem *pField = new FieldItem;
	if(pField == NULL)
		return -1;

	memset(pField, 0, sizeof(FieldItem));
	pField->bKeyField = bIsKeyField;
	pField->nFieldLen = inFieldLen;
	strcpy(pField->szFieldName, inFieldName);
	m_tFieldList.push_back(pField);
	printf("[CSessionShm::AddFields] Add New Field:%p name:%s len:%d\n", pField, inFieldName, inFieldLen);
	return 0;
}

int	CSessionShm::GetAllFieldsLen()
{
	CFieldList::const_iterator item = m_tFieldList.begin();
	int nAddFieldsLen = 0;
	while (item != m_tFieldList.end())
	{
		nAddFieldsLen += (*item)->nFieldLen;
		item++;	
	}

	return nAddFieldsLen;
}

int	CSessionShm::GetKeyFieldOffset()
{
	CFieldList::const_iterator item = m_tFieldList.begin();
	int nAddFieldsLen = 0;
	while (item != m_tFieldList.end())
	{
		if((*item)->bKeyField)
			break;

		nAddFieldsLen += (*item)->nFieldLen;
		item++;	
	}

	return nAddFieldsLen;
}

#ifdef WIN32
void* CSessionShm::Shm_Create(char* shmName, int inMaxRow, int *error)
{

	if(shmName==NULL)
		return NULL;
	int size = FIELD_ITEM_LEN +  // 4 + 4 + 4 + 24
			   FIELD_ITEM_LEN * m_tFieldList.size() +
			   inMaxRow * GetAllFieldsLen();
	strcpy(m_szShareMemName, shmName);

	m_hMapFile = CreateFileMapping( (HANDLE)0xFFFFFFFF,NULL,
					PAGE_READWRITE,0,size,shmName);
	if(m_hMapFile == NULL || GetLastError() == ERROR_ALREADY_EXISTS) 
	{ 
		if(m_hMapFile)
		{
			CloseHandle(m_hMapFile); 
			m_hMapFile = NULL;
		}
		*error = 1;		
		return NULL;
	} 
	m_nShareMemSize = size;
	m_bIsCreated = true;
	return m_hMapFile;
}

int CSessionShm::Shm_Delete(char* shmName)
{
	if(m_hMapFile)
	{
		CloseHandle(m_hMapFile); 
		m_hMapFile = NULL;
		m_bIsCreated = false;
	}
	return 1;		//success//
}

int CSessionShm::Shm_Open(char* shmName, int mode)
{
	if(shmName==NULL)
		return -1;
	strcpy(m_szShareMemName, shmName);

	m_hShareMem = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shmName);
	if(m_hShareMem)
	{
		if(mode==en_WRITE_MODE)	
			m_pShareMemMap = MapViewOfFile(m_hShareMem, FILE_MAP_WRITE, 0, 0, 0);
		else if(mode==en_READ_MODE)
			m_pShareMemMap = MapViewOfFile(m_hShareMem, FILE_MAP_READ, 0, 0, 0);
		else if(mode==en_ALL_ACCESS_MODE)
			m_pShareMemMap = MapViewOfFile(m_hShareMem, FILE_MAP_ALL_ACCESS, 0, 0, 0);
		if(m_pShareMemMap)
		{
			if(	m_bIsCreated )
				InitShareMemHead();
			else
				InitFields();

			return 0;
		}
		else
			return -2;
	}
	else
		return -2;
	
}



int CSessionShm::Shm_Close()
{
	if(m_pShareMemMap != NULL)
	{
		UnmapViewOfFile(m_pShareMemMap);
		m_pShareMemMap = NULL;
	}
	if(m_hShareMem)
	{
		CloseHandle((void*)m_hShareMem);
		m_hShareMem = NULL;
	}
	return 1;
}

#else
extern int errno;
void* CSessionShm::Shm_Create(char* shmName, int inMaxRow, int *error)
{
	int fd;	
	Shm_Delete(shmName);
	int size = FIELD_ITEM_LEN +  // 4 + 4 + 4 + 24
			   FIELD_ITEM_LEN * m_tFieldList.size() +
			   inMaxRow * GetAllFieldsLen();

	strcpy(m_szShareMemName, shmName);
	fd = shm_open(shmName, O_CREAT | O_RDWR | O_EXCL, 0666);
	if(fd<0)
	{
		printf("[Shm_Create] create error, name=%s,size=%d\n", shmName, size);
		if(errno==EEXIST)
              {
               	printf("[Shm_Create] create error,EEXIST, name=%s,size=%d\n", shmName, size);
			if(error)
				*error = 1;
              }
              return NULL;
	}

	if(ftruncate(fd, size) < 0)
	{
			shm_unlink(shmName);
			return NULL;
	}

	close(fd);
	m_nShareMemSize = size;
	m_bIsCreated = true;

	printf("[Shm_Create] create success, name=%s,size=%d\n", shmName, size);
	return shmName;
}

int CSessionShm::Shm_Delete(char* shmName)
{
	int result; 
	if(shmName == NULL)
	{
		result = shm_unlink(m_szShareMemName);
	}
	else
	{
		result = shm_unlink(shmName);
	}
	
	m_bIsCreated = false;

	if(result == -1) 
		return 0;

	return 1;
}

int CSessionShm::Shm_Open(char* shmName, int mode)
{
	struct stat tmpStat;

	char szShmPath[256] = { 0 };
	strcpy(szShmPath, "/dev/shm/");
	strcat(szShmPath, shmName);
	strcpy(m_szShareMemName, shmName);

	if(mode==en_READ_MODE)
		m_hShareMem=open(szShmPath, O_RDONLY, 0);
	else if(mode==en_WRITE_MODE)
		m_hShareMem=open(szShmPath, O_WRONLY, 0);
	else if(mode==en_ALL_ACCESS_MODE)
		m_hShareMem=open(szShmPath, O_RDWR, 0);
	if(m_hShareMem == -1)
	{
		printf("[Shm_Open] open error, shareName=%s\n", shmName);
		return -1;
	}	

	memset(&tmpStat, 0, sizeof(tmpStat));
	if(fstat(m_hShareMem,&tmpStat) != 0)
	{
		printf("[Shm_Open] fstat error, shareName=%s\n", shmName);
		return -1;
	}	

	if(mode==en_READ_MODE)
		m_pShareMemMap = mmap(NULL,tmpStat.st_size,PROT_READ,MAP_SHARED,m_hShareMem,0);	
	else if(mode==en_WRITE_MODE || mode==en_ALL_ACCESS_MODE)
		m_pShareMemMap = mmap(NULL,tmpStat.st_size, PROT_READ | PROT_WRITE,MAP_SHARED,m_hShareMem,0);
	if(m_pShareMemMap == NULL || m_pShareMemMap == MAP_FAILED)
	{
		printf("[Shm_Open] mmap error, shareName=%s, size=%d\n", shmName, tmpStat.st_size);
		return -1;
	}
	if(	m_bIsCreated )
		InitShareMemHead();
	else
		InitFields();
	m_nShareMemSize = tmpStat.st_size;

	return 0;
}


int CSessionShm::Shm_Close()
{
	
	if(m_pShareMemMap != NULL)
	{
		if(munmap((void*)m_pShareMemMap, m_nShareMemSize) < 0)
			printf("[Shm_Close] munmap Error! \n");
		else
			printf("[Shm_Close] munmap OK!\n");    
		m_pShareMemMap = NULL;
	}

	if (m_hShareMem)//add by suijz on 2010-09-21
	{
            close(m_hShareMem);
	    m_hShareMem = 0;
        }

	FieldItem* pField = NULL;
	while(m_tFieldList.size() > 0)
	{
		pField = (FieldItem*)m_tFieldList.front();
		m_tFieldList.pop_front();
		delete pField;
	};
	m_tFieldList.clear();

	return 1;
}

#endif

int CSessionShm::Shm_Get_Size()
{
	return m_nShareMemSize;
}

int CSessionShm::InitShareMemHead()
{
	if(m_pShareMemMap == NULL)
		return -1;
	long *pMemMap = (long *)m_pShareMemMap;
	*pMemMap = time(NULL);
	pMemMap ++;

	*pMemMap = 0;
	pMemMap ++;

	*pMemMap = m_tFieldList.size();

	char *pFieldMem = (char*)m_pShareMemMap + FIELD_ITEM_LEN;

	CFieldList::const_iterator item = m_tFieldList.begin();
	int nAddFieldsLen = 0;
	while (item != m_tFieldList.end())
	{
		if(strlen((*item)->szFieldName) > MAX_FIELD_NAME_LEN)
			memcpy(pFieldMem, (*item)->szFieldName, MAX_FIELD_NAME_LEN -1);
		else
			strcpy(pFieldMem, (*item)->szFieldName);
		pFieldMem += MAX_FIELD_NAME_LEN;

		*((int*)pFieldMem) = (*item)->nFieldLen;
		pFieldMem += 4;
		
		item++;	
	}

	return 0;
}

int	 CSessionShm::InitFields()
{
	if(m_pShareMemMap == NULL)
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;
	pMemMap ++;

	pMemMap ++;

	long nFieldNum = *pMemMap;

	char * pFieldMap = (char*)m_pShareMemMap + FIELD_ITEM_LEN;
	for(long i=0; i<nFieldNum; i++)
	{
		FieldItem *pField = new FieldItem;
		if(pField == NULL)
			return -1;

		memset(pField, 0, sizeof(FieldItem));
		memcpy(pField->szFieldName, (char*)pFieldMap, MAX_FIELD_NAME_LEN);
		pFieldMap += MAX_FIELD_NAME_LEN;

		pField->nFieldLen = *((long*)pFieldMap);
		pFieldMap += 4;

		if(m_tFieldList.size() == 0)
			pField->bKeyField = true;

		m_tFieldList.push_back(pField);
		printf("[CSessionShm::AddFields] Add New Field:%p name:%s len:%d\n", pField, pField->szFieldName, pField->nFieldLen);
	}

	return 0;
}

int CSessionShm::Shm_AppendSessionInfo(void *pSessionInfo, int inInfoLen)
{
	if(m_pShareMemMap == NULL || pSessionInfo == NULL || inInfoLen != GetAllFieldsLen())
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;
	*pMemMap = time(NULL);
	pMemMap ++;

	int nRowNum = *pMemMap;
	int nHeadSize = FIELD_ITEM_LEN +  // 4 + 4 + 4 + 24
			   FIELD_ITEM_LEN * m_tFieldList.size();

	memcpy((char*)m_pShareMemMap + nHeadSize + nRowNum * GetAllFieldsLen(), (char*)pSessionInfo, inInfoLen);
	*pMemMap = nRowNum + 1;

	return 0;
}


int CSessionShm::Shm_UpdateSessionInfo(void* pKeyFieldValue, int inKeyFieldValueLen, void *pSessionInfo, int inInfoLen)
{
	if(m_pShareMemMap == NULL || pSessionInfo == NULL || inInfoLen != GetAllFieldsLen())
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;
	*pMemMap = time(NULL);
	pMemMap ++;

	int nRowNum = *pMemMap;
	int nHeadSize = FIELD_ITEM_LEN +  // 4 + 4 + 4 + 24
			   FIELD_ITEM_LEN * m_tFieldList.size();
	int nAllFieldsLen = GetAllFieldsLen();
	int nKeyFieldOffset = GetKeyFieldOffset();
	bool bFind = false;
	for(int i=0; i< nRowNum; i++)
	{
		if(memcmp((char*)m_pShareMemMap + nHeadSize + i * nAllFieldsLen + nKeyFieldOffset, (char*)pKeyFieldValue, inKeyFieldValueLen) == 0)
		{
			memcpy((char*)m_pShareMemMap + nHeadSize + i * nAllFieldsLen, (char*)pSessionInfo, inInfoLen);
			bFind = true;
			break;
		}
	}

	if(!bFind)
		return -2;

	return 0;
}

int CSessionShm::Shm_DeleteSessionInfo(void* pKeyFieldValue, int inKeyFieldValueLen)
{
	if(m_pShareMemMap == NULL || pKeyFieldValue == NULL)
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;
	*pMemMap = time(NULL);
	pMemMap ++;

	int nRowNum = *pMemMap;
	int nHeadSize = FIELD_ITEM_LEN +  // 4 + 4 + 4 + 24
			   FIELD_ITEM_LEN * m_tFieldList.size();
	int nAllFieldsLen = GetAllFieldsLen();
	int nKeyFieldOffset = GetKeyFieldOffset();
	bool bFind = false;
	for(int i=0; i< nRowNum; i++)
	{
		if(memcmp((char*)m_pShareMemMap + nHeadSize + i * nAllFieldsLen + nKeyFieldOffset, (char*)pKeyFieldValue, inKeyFieldValueLen) == 0)
		{
			memcpy((char*)m_pShareMemMap + nHeadSize + i * nAllFieldsLen, (char*)m_pShareMemMap + nHeadSize + (i + 1) * nAllFieldsLen, (nRowNum - i - 1) * nAllFieldsLen);
			nRowNum --;
			*pMemMap = nRowNum;

			bFind = true;
			break;
		}
	}

	if(!bFind)
		return -2;

	return 0;
}

int CSessionShm::Shm_DeleteAllSessionInfo()
{
	if(m_pShareMemMap == NULL)
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;
	*pMemMap = time(NULL);
	pMemMap ++;

	*pMemMap = 0;

	return 0;
}

int CSessionShm::Shm_ReadSessionInfo(void* pKeyFieldValue, int inKeyFieldValueLen, void *pSessionInfo, int *outInfoLen)
{
	if(m_pShareMemMap == NULL || pSessionInfo == NULL)
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;
	pMemMap ++;

	int nRowNum = *pMemMap;
	int nHeadSize = FIELD_ITEM_LEN +  // 4 + 4 + 4 + 24
			   FIELD_ITEM_LEN * m_tFieldList.size();
	int nAllFieldsLen = GetAllFieldsLen();
	int nKeyFieldOffset = GetKeyFieldOffset();
	bool bFind = false;
	for(int i=0; i< nRowNum; i++)
	{
		if(memcmp((char*)m_pShareMemMap + nHeadSize + i * nAllFieldsLen + nKeyFieldOffset, (char*)pKeyFieldValue, inKeyFieldValueLen) == 0)
		{
			memcpy((char*)pSessionInfo, (char*)m_pShareMemMap + nHeadSize + i * nAllFieldsLen, nAllFieldsLen);
			if(outInfoLen)
				*outInfoLen = nAllFieldsLen;
			bFind = true;
			break;
		}
	}

	if(!bFind)
		return -2;

	return 0;
}

int CSessionShm::Shm_ReadSessionInfo(int inSessionIndex, void *pSessionInfo, int *outInfoLen)
{
	if(m_pShareMemMap == NULL || pSessionInfo == NULL)
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;
	pMemMap ++;

	int nRowNum = *pMemMap;
	if(inSessionIndex >= nRowNum)
		return -2;

	int nHeadSize = FIELD_ITEM_LEN +  // 4 + 4 + 4 + 24
			   FIELD_ITEM_LEN * m_tFieldList.size();
	int nAllFieldsLen = GetAllFieldsLen();

	memcpy((char*)pSessionInfo, (char*)m_pShareMemMap + nHeadSize + inSessionIndex * nAllFieldsLen, nAllFieldsLen);
	if(outInfoLen)
		*outInfoLen = nAllFieldsLen;


	return 0;
}
	
long CSessionShm::Shm_Get_UpdateTime()
{
	if(m_pShareMemMap == NULL)
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;
	
	return *pMemMap;
}

long CSessionShm::Shm_Get_RowNum()
{
	if(m_pShareMemMap == NULL)
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;

	pMemMap ++;

	return *pMemMap;
}

long CSessionShm::Shm_Get_FieldsNum()
{
	if(m_pShareMemMap == NULL)
		return -1;

	long *pMemMap = (long *)m_pShareMemMap;

	pMemMap += 2;
	
	return *pMemMap;
}

int CSessionShm::Shm_Get_FieldItem(int index, FieldItem * piField)
{
	if (NULL == piField || index < 0 || m_tFieldList.size() <= index)
		return -1;

	CFieldList::const_iterator item = m_tFieldList.begin();

	int i = 0;
	FieldItem* pItem = NULL;
	while (item != m_tFieldList.end())
	{
		if(i == index)
		{
			pItem = (FieldItem*)(*item);
			strcpy(piField->szFieldName, (*item)->szFieldName);
			piField->nFieldLen = pItem->nFieldLen;
			piField->bKeyField = pItem->bKeyField;

			break;
		}
	
		i ++;
		item++;	
	}

	return 0;
}

int CSessionShm::GetFieldOffset(int index)
{
	if (index < 0 || m_tFieldList.size() <= index)
		return -1;

	CFieldList::const_iterator item = m_tFieldList.begin();

	int i = 0;
	int nAddFieldsLen = 0;
	while (item != m_tFieldList.end())
	{
		if(i == index)
		{
			break;
		}

		nAddFieldsLen += (*item)->nFieldLen;
	
		i ++;
		item++;	
	}

	return nAddFieldsLen;
}

int CSessionShm::Shm_GetFieldFromSessionInfo(void *pSessionInfo, int inInfoLen, int inFieldNo, void* outFieldValue, int inFieldLen)
{
	if (NULL == pSessionInfo || inFieldNo < 0 || m_tFieldList.size() <= inFieldNo || outFieldValue == NULL)
		return -1;

	int nFieldOffset = GetFieldOffset(inFieldNo);

	memcpy((char*)outFieldValue, (char*)pSessionInfo + nFieldOffset, inFieldLen);

	return 0;
}
